package com.lkf.simplewebcontainer.container;

import com.lkf.simplewebcontainer.http.Request;
import com.lkf.simplewebcontainer.http.Response;
import com.lkf.simplewebcontainer.http.impl.SimpleRequest;
import com.lkf.simplewebcontainer.http.impl.SimpleResponse;
import com.lkf.simplewebcontainer.servlet.DefaultServlet;
import com.lkf.simplewebcontainer.servlet.FileServlet;
import com.lkf.simplewebcontainer.servlet.NotFoundServlet;
import com.lkf.simplewebcontainer.servlet.Servlet;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpRequest;

import java.io.File;
import java.util.Map;

/**
 * 网络容器实现类的助手类，与Server类解耦，用于从Channel中读取数据后进行具体的业务实现
 */
public class WebContainerHandler extends ChannelInboundHandlerAdapter {
    // 静态资源地址
    private String staticPath;
    // 接收Server初始化及动态加载的Servlet实例信息
    private Map<String, Servlet> servletMap;
    // 存放Servlet简单类名和全限定类名对应的集合
    private Map<String, String> servletNameMap;

    public WebContainerHandler(Map<String, Servlet> servletMap, Map<String, String> servletNameMap, String staticPath) {
        this.servletMap = servletMap;
        this.servletNameMap = servletNameMap;
        this.staticPath = staticPath;
    }

    /**
     * 读取Channel上下文操作和传递对象
     *
     * @param ctx Channel上下文操作
     * @param msg Channel传递的对象
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;
            String uri = request.uri();
//            System.out.println("uri:" + uri);
            // 静态资源类型请求
            if ((!uri.contains("?")) && (!uri.endsWith("/"))) {
                handleFile(ctx, request);
            }
            // Servlet类型请求
            else {
                handleServlet(ctx, request);
            }
            ctx.close();
        }
    }

    /**
     * 捕获异常
     *
     * @param ctx   Channel上下文操作
     * @param cause 异常
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * 处理Servlet请求
     *
     * @param ctx
     * @param request
     * @throws Exception
     */
    public void handleServlet(ChannelHandlerContext ctx, HttpRequest request) throws Exception {
        String uri = request.uri();
        // 从请求中解析出要访问的Servlet名称
        //aaa/bbb/twoservlet?name=aa
        String servletName = "";
        if (uri.contains("?") && uri.contains("/")) {
            servletName = uri.substring(uri.lastIndexOf("/") + 1, uri.indexOf("?"));
        }
//        System.out.println("servletName:" + servletName);
        Servlet servlet = new DefaultServlet();
        Request req = new SimpleRequest(request);
        Response res = new SimpleResponse(request, ctx);
        //第一次访问，Servlet是不会被加载的
        //初始化加载的只是类全限定名称，懒加载
        //如果访问Servlet才会去初始化它对象
        if (servletMap.containsKey(servletName)) {
            servlet = servletMap.get(servletName);
        } else if (servletNameMap.containsKey(servletName)) {
            // double-check，双重检测锁：为什么要在锁前判断一次，还要在锁后继续判断一次？
            // 锁前判断，初步检查是否存在Servlet实例
            if (servletMap.get(servletName) == null) {
                synchronized (this) {
                    // 锁后判断，检查是否有其他线程创建了该Servlet实例
                    if (servletMap.get(servletName) == null) {
                        // 获取当前Servlet的全限定性类名
                        String className = servletNameMap.get(servletName);
                        // 使用反射机制创建Servlet实例
                        servlet = (Servlet) Class.forName(className).newInstance();
                        // 将Servlet实例写入到nameToServletMap
                        servletMap.put(servletName, servlet);
                    }
                }
            }
        } else {
            System.out.println("不存在" + servletName);
            Servlet notFoundServlet = new NotFoundServlet("Servlet不存在！");
            notFoundServlet.doGet(req, res);
        }
        // 根据不同的请求类型，调用servlet实例的不同方法
        if (request.method().name().equalsIgnoreCase("GET")) {
            servlet.doGet(req, res);
        } else if (request.method().name().equalsIgnoreCase("POST")) {
            servlet.doPost(req, res);
        }
    }

    /**
     * 处理静态资源请求
     *
     * @param ctx
     * @param request
     * @throws Exception
     */
    public void handleFile(ChannelHandlerContext ctx, HttpRequest request) throws Exception {
        String uri = request.uri();
        File file = new File(staticPath + uri);
        Request req = new SimpleRequest(request);
        Response res = new SimpleResponse(request, ctx);
        if (!file.exists()) {
            Servlet notFoundServlet = new NotFoundServlet("资源不存在！");
            notFoundServlet.doGet(req, res);
        } else {
            Servlet fileServlet = new FileServlet(staticPath, file);
            // 根据不同的请求类型，调用servlet实例的不同方法
            if (request.method().name().equalsIgnoreCase("GET")) {
                fileServlet.doGet(req, res);
            } else if (request.method().name().equalsIgnoreCase("POST")) {
                fileServlet.doPost(req, res);
            }
        }
    }
}
